using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.IO;
using System.Runtime.InteropServices;
using System.Xml;
using System.Diagnostics;
using System.Security.Principal;

namespace CKS.EBE
{
    public class MetaWeblogHandler
    {
        #region "Win32"
        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool LogonUser(
          string principal,
          string authority,
          string password,
          LogonSessionType logonType,
          LogonProvider logonProvider,
          out IntPtr token);
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool CloseHandle(IntPtr handle);
        enum LogonSessionType : uint
        {
            Interactive = 2,
            Network,
            Batch,
            Service,
            NetworkCleartext = 8,
            NewCredentials
        }
        enum LogonProvider : uint
        {
            Default = 0, // default for platform (use this!)
            WinNT35,     // sends smoke signals to authority
            WinNT40,     // uses NTLM
            WinNT50      // negotiates Kerb or NTLM
        }
        #endregion

        public static void HandleMetaWeblogRequest(HttpApplication context)
        {
            LogonMetablogApiUser();
            API.MetaWeblog m = new API.MetaWeblog();
            StreamReader sr = new StreamReader(m.Invoke(context.Request.InputStream));
            context.Response.Write(sr.ReadToEnd());
            context.Response.End();
        }

        protected static void LogonMetablogApiUser()
        {
            long pos = HttpContext.Current.Request.InputStream.Position;
            System.IO.StreamReader sr = new System.IO.StreamReader(HttpContext.Current.Request.InputStream);
            string sRequestText = sr.ReadToEnd();
            HttpContext.Current.Request.InputStream.Position = pos;

            XmlDocument oDoc = new XmlDocument();
            oDoc.LoadXml(sRequestText);

            string sMethodName = oDoc.SelectSingleNode("methodCall/methodName").InnerText;

            XmlNodeList oParameters = oDoc.SelectNodes(".//param");

            if (sMethodName.Contains("getUsersBlogs") || sMethodName.Contains("editPost") || sMethodName.Contains("getCategories") || sMethodName.Contains("getPost") || sMethodName.Contains("getRecentPosts") || sMethodName.Contains("getUserInfo") || sMethodName.Contains("newMediaObject") || sMethodName.Contains("newPost"))
            {
                string sUserName = oParameters[1].SelectSingleNode("value/string").InnerText;
                string sPassword = oParameters[2].SelectSingleNode("value/string").InnerText;
                ValidateAndImpersonateUser(sUserName, sPassword);
            }
            else if (sMethodName.Contains("deletePost"))
            {
                string sUserName = oParameters[2].SelectSingleNode("value/string").InnerText;
                string sPassword = oParameters[3].SelectSingleNode("value/string").InnerText;
                ValidateAndImpersonateUser(sUserName, sPassword);
            }
        }

        protected static bool ValidateAndImpersonateUser(string username, string password)
        {
            IntPtr token = IntPtr.Zero;

            string sUser = username;
            string sDomain = "";

            if (username.Contains("/"))
            {
                string[] arUser = username.Split('/');
                sUser = arUser[1];
                sDomain = arUser[0];
            }

            if (username.Contains("\\"))
            {
                string[] arUser = username.Split('\\');
                sUser = arUser[1];
                sDomain = arUser[0];
            }

            bool result = LogonUser(sUser, sDomain,
                                    password,
                                    LogonSessionType.Network,
                                    LogonProvider.Default,
                                    out token);

            if (result == false)
            {
                Debug.WriteLine("Invalid logon: " + username);
                throw new Exception("Invalid UserName or Password");
            }

            System.Security.Principal.WindowsIdentity oIdentity = new System.Security.Principal.WindowsIdentity(token);
            oIdentity.Impersonate();
            // Yes you do need to do this twice...it doesn't work otherwise
            WindowsIdentity.GetCurrent().Impersonate();

            HttpContext.Current.User = new WindowsPrincipal(oIdentity);

            return true;
        }

    }
}
